﻿using System;
using Nofs.Net.nofs.metadata.interfaces;
using biz.ritter.javapi.lang;
using biz.ritter.javapi.lang.reflect;

namespace Nofs.Net.nofs.metadata.XMLDriver
{

    public class XMLGetterSetterPair : IGetterSetterPair
    {
        private readonly Object _obj;
        private readonly Method _getter;
        private readonly Method _setter;

        public XMLGetterSetterPair(Object obj, Class parameterType, String methodName)
        {
            _obj = obj;
            _getter = FindGetterMethod(parameterType, methodName, obj.getClass());
            _setter = FindSetterMethod(parameterType, methodName, obj.getClass());
        }

        private static bool AcceptGetterMethodName(String expected, String actual)
        {
            if (expected.compareTo(actual) == 0)
            {
                return true;
            }
            if (actual.startsWith("get") && actual.substring(3).compareTo(actual) == 0)
            {
                return true;
            }
            return false;
        }

        private static bool AcceptSetterMethodName(String expected, String actual)
        {
            if (expected.compareTo(actual) == 0)
            {
                return true;
            }
            if (actual.startsWith("set") && actual.substring(3).compareTo(actual) == 0)
            {
                return true;
            }
            return false;
        }

        private static Method FindGetterMethod(Class parameterType, String name, Class objectType)
        {
            foreach (Method method in objectType.getMethods())
            {
                if (AcceptGetterMethodName(name, method.getName()) &&
                    method.getReturnType() == parameterType &&
                    method.getParameterTypes().Length == 0)
                {
                    return method;
                }
            }
            return null;
        }

        private static Method FindSetterMethod(Class parameterType, String name, Class objectType)
        {
            foreach (Method method in objectType.getMethods())
            {
                if (AcceptSetterMethodName(name, method.getName()) &&
                    method.getReturnType() == typeof(void).getClass() &&
                    method.getParameterTypes().Length == 1 &&
                    method.getParameterTypes()[0] == parameterType)
                {
                    return method;
                }
            }
            return null;
        }

        public Object Getter() //throws IllegalArgumentException,	IllegalAccessException, InvocationTargetException 
        {
            return _getter.invoke(_obj, (Object[])null);
        }

        public bool GetterExists()
        {
            return _getter != null;
        }

        public void Setter(Object value) //throws IllegalArgumentException, IllegalAccessException, InvocationTargetException 
        {
            _setter.invoke(_obj, value);
        }

        public bool SetterExists()
        {
            return _setter != null;
        }
    }
}
